package com.duobaoyu.dby.supply.message.listener.hander.order;

import cn.hutool.core.lang.Pair;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSON;
import com.duobaoyu.dby.channel.adapter.enums.ChannelCodeEnum;
import com.duobaoyu.dby.channel.adapter.enums.biz.config.GlobalErrorCodeEnum;
import com.duobaoyu.dby.channel.adapter.enums.biz.order.OrderStatusEnum;
import com.duobaoyu.dby.channel.adapter.util.ChannelCodeUtils;
import com.duobaoyu.dby.channel.common.util.DingDingExtUtils;
import com.duobaoyu.dby.channel.common.util.SupplyCollectionUtils;
import com.duobaoyu.dby.common.core.constant.CommonConstants;
import com.duobaoyu.dby.common.core.constant.StringPool;
import com.duobaoyu.dby.common.mybatis.util.EnumUtils;
import com.duobaoyu.dby.saas.product.common.remote.dto.PlatformPriceCheckDTO;
import com.duobaoyu.dby.supply.biz.client.boundary.order.OrderBoundaryClient;
import com.duobaoyu.dby.supply.biz.client.boundary.order.bean.bo.*;
import com.duobaoyu.dby.supply.biz.client.product.ProductCenterApiClient;
import com.duobaoyu.dby.supply.biz.client.product.bean.bo.PlatformPriceCheckBO;
import com.duobaoyu.dby.supply.biz.constant.OperateSourceConstants;
import com.duobaoyu.dby.supply.biz.constant.OrderOperateConstants;
import com.duobaoyu.dby.supply.biz.enums.OrderParentTypeEnum;
import com.duobaoyu.dby.supply.biz.enums.OrderTagEnum;
import com.duobaoyu.dby.supply.biz.enums.RedisKeys;
import com.duobaoyu.dby.supply.biz.producer.SupplyChainMQProducer;
import com.duobaoyu.dby.supply.biz.producer.constant.SupplyChainMQConstants;
import com.duobaoyu.dby.supply.biz.producer.message.OrderConfirmMessage;
import com.duobaoyu.dby.supply.biz.service.order.OrderRepairService;
import com.duobaoyu.dby.supply.biz.service.order.OrderService;
import com.duobaoyu.dby.supply.biz.service.order.event.OrderConfirmSuccessEvent;
import com.duobaoyu.dby.supply.core.cache.service.RedissonService;
import com.duobaoyu.dby.supply.core.dinger.annotation.DingerTalk;
import com.duobaoyu.dby.supply.core.rocketmq.handler.AbstractClusterMessageHandler;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.rocketmq.common.message.MessageExt;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 确认订单消息
 *
 * @author chenms
 * @date 2023/10/07 10:58
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class OrderConfirmMessageHandler extends AbstractClusterMessageHandler<OrderConfirmMessage> {

    private final OrderService orderService;
    private final OrderBoundaryClient orderBoundaryClient;
    private final SupplyChainMQProducer supplyChainMQProducer;
    private final OrderRepairService orderRepairService;
    private final TransactionTemplate transactionTemplate;
    private final ProductCenterApiClient productCenterApiClient;
    private final RedissonService redissonService;

    @Override
    public String getTopic() {
        return SupplyChainMQConstants.SupplyChainTopic.ORDER_TOPIC;
    }

    @Override
    public String getTag() {
        return SupplyChainMQConstants.SupplyChainTopic.OrderTag.ORDER_CONFIRM;
    }

    @Override
    @DingerTalk(title = "供应链渠道确认订单消息Consumer")
    public boolean messageHandler(OrderConfirmMessage orderConfirmMessage, MessageExt messageExt) {
        // 根据消息id纬度加锁,防止处理时间过长消息响应超时重复消费导致在渠道多次下单
        return redissonService.tryLock(RedisKeys.LOCK_REDIS.formatKey(messageExt.getMsgId()), ()->{
            DingDingExtUtils.sendMarkdownMsg(String.format("确认订单consumer未获得分布式锁, 消息id=%s", messageExt.getMsgId()));
            if(log.isDebugEnabled()) {
                log.debug("确认订单消息处理未获得分布式锁, 消息处理结束: orderConfirmMessage={}, msgId={}", orderConfirmMessage, messageExt.getMsgId());
            }
            return true;
        },()->{
            try {
                if(log.isDebugEnabled()) {
                    log.debug("开始处理确认订单消息, param={}", JSON.toJSONString(orderConfirmMessage));
                }
                List<OrderBO> orderList = orderService.list(OrderQueryInBO.builder()
                        .supplyTradeSn(orderConfirmMessage.getSupplyTradeSn())
                        .orderSnList(orderConfirmMessage.getOrderSnList())
                        .returnConsignee(Boolean.TRUE)
                        .returnProduct(Boolean.TRUE)
                        .parentType(OrderParentTypeEnum.AFTER_SPLIT.getValue()).build());
                if (log.isDebugEnabled()) {
                    log.debug("确认订单数据: {}", JSON.toJSONString(orderList));
                }
                boolean valid = this.validOrder(orderList, orderConfirmMessage);
                if (!valid) {
                    if(log.isDebugEnabled()) {
                        log.debug("确认订单消息处理结束, 消息校验失败 orders={}", JSON.toJSONString(orderList));
                    }
                    return Boolean.TRUE;
                }
                ValidResult validResult = validOrderProduct(orderList);
                // 商品校验通过的订单数据
                List<OrderBO> successList = validResult.getSuccessList();
                if (CollectionUtils.isNotEmpty(successList)) {
                    OrderBO order = SupplyCollectionUtils.getSingleDataFirst(successList, OrderBO::new);
                    String orderTag = order.getOrderTag();
                    if(log.isDebugEnabled()) {
                        log.debug("交易单标签:{}", orderTag);
                    }
                    OrderConfirmResultBO orderConfirmResult = OrderTagEnum.isLargeAmountOrder(orderTag) ? orderBoundaryClient.submitAndConfirmOrder(successList) : orderBoundaryClient.confirmPreOrder(successList);
                    if(log.isDebugEnabled()) {
                        log.debug("调用渠道确认订单结果: {}", JSON.toJSONString(orderConfirmResult));
                    }

                    Map<String, OrderBO> orderMap = orderList.stream().collect(Collectors.toMap(OrderBO::getOrderSn, Function.identity()));

                    // 处理失败的订单
                    Optional.ofNullable(orderConfirmResult.getFailedList()).orElse(Collections.emptyList())
                            .forEach(failure -> this.handleConfirmFailureOrder(orderMap.get(failure.getOrderSn()), failure));

                    // 处理成功的订单
                    Optional.ofNullable(orderConfirmResult.getConfirmSuccessList()).orElse(Collections.emptyList())
                            .forEach(confirmSuccess -> this.handleConfirmSuccessOrder(orderMap.get(confirmSuccess.getOrderSn()), confirmSuccess));
                }
                List<ErrorOrder> errorOrderList = validResult.getErrorOrderList();
                if (CollectionUtils.isNotEmpty(errorOrderList)) {
                    // 处理订单商品成本价或状态校验异常的订单
                    errorOrderList.forEach(this::handleValidFailOrder);
                }
            } catch (Exception e) {
                log.warn("确认订单消息处理失败,data:{}", orderConfirmMessage, e);
                return false;
            }
            return true;
        });
    }

    /**
     * 校验失败的订单进入异常单
     */
    private void handleValidFailOrder(ErrorOrder errorOrder) {
        try {
            OrderBO order = errorOrder.getOrder();
            transactionTemplate.executeWithoutResult(transactionStatus -> {
                UpdateOrderBO updateOrder = new UpdateOrderBO();
                updateOrder.setOrderSn(order.getOrderSn());
                updateOrder.setSource(OperateSourceConstants.SYSTEM);
                updateOrder.setDescription(OrderOperateConstants.SYSTEM_ASYNC_CONFIRM_ORDER);
                String errorInfo = errorOrder.errorMessage(CommonConstants.HUNDRED * CommonConstants.TWO);
                updateOrder.setErrorInfo(errorInfo);
                updateOrder.setOrderTag(order.addTag(OrderTagEnum.REPAIRING.getValue()));
                updateOrder.setOrderStatus(Pair.of(order.getOrderStatus(), OrderStatusEnum.FAILURE.getValue()));
                updateOrder.setLogChangeItemList(order.diff(updateOrder).getDiffs());
                boolean b = orderService.updateOrderByOrderSn(updateOrder);
                if (!b) {
                    log.info("处理确认失败订单更新订单失败: updateOrderBO={}", JSON.toJSONString(updateOrder));
                    return;
                }
                SaveOrderRepairBO saveOrderRepair = orderRepairService.genSaveOrderRepair(order, String.valueOf(errorOrder.getFirstErrorCode()), errorInfo);
                orderRepairService.saveRepairOrderList(Lists.newArrayList(saveOrderRepair));
            });
        } catch (Exception e) {
            log.warn("确认订单处理校验失败的订单发生异常: errorOrder={}", JSON.toJSONString(errorOrder), e);
        }
    }

    /**
     * 处理确认成功的订单
     *
     * @param order
     * @param confirmSuccess
     */
    private void handleConfirmSuccessOrder(OrderBO order, OrderConfirmResultBO.ConfirmSuccessBO confirmSuccess) {
        try {
            UpdateOrderBO updateOrder = new UpdateOrderBO();
            updateOrder.setOrderSn(order.getOrderSn());
            updateOrder.setSource(OperateSourceConstants.SYSTEM);
            updateOrder.setDescription(OrderOperateConstants.SYSTEM_ASYNC_CONFIRM_ORDER);
            updateOrder.setChannelTradeOrderSn(confirmSuccess.getChannelTradeOrderSn());
            updateOrder.setChannelOrderSn(Optional.ofNullable(confirmSuccess.getChannelTradeOrderSn()).orElse(order.getChannelTradeOrderSn()));
            // 非处理中的订单状态改为待发货状态
            Integer statusNew = EnumUtils.neq(OrderStatusEnum.RECHARGE, confirmSuccess.getStatus()) ? OrderStatusEnum.WAIT_SHIP.getValue() : OrderStatusEnum.RECHARGE.getValue();
            updateOrder.setOrderStatus(Pair.of(order.getOrderStatus(), statusNew));
            ChannelCodeEnum channelCodeEnumByCode = ChannelCodeEnum.getChannelCodeEnumByCode(order.getChannelCode());
            if (ChannelCodeUtils.supportImmediateAfterSalesChannelsAfterConfirmOrder().contains(channelCodeEnumByCode)) {
                updateOrder.setAfterSalesAllowed(Boolean.TRUE);
            }
            updateOrder.setLogChangeItemList(order.diff(updateOrder).getDiffs());
            boolean b = orderService.updateOrderByOrderSn(updateOrder);
            if (!b) {
                log.info("处理确认成功订单更新订单失败: updateOrderBO={}", JSON.toJSONString(updateOrder));
                return;
            }

            SpringUtil.publishEvent(new OrderConfirmSuccessEvent(order.update(updateOrder), confirmSuccess));

            // 如果状态变更通知业务方
            if (Objects.equals(order.getOrderStatus(), statusNew)) {
                supplyChainMQProducer.orderAlterSend(order.getSupplyTradeSn(), order.getServerName());
            }

        } catch (Exception e) {
            log.warn("处理确认成功订单发生异常: [orderBO={},failureBO={}]", JSON.toJSONString(order), JSON.toJSONString(confirmSuccess), e);
        }
    }

    /**
     * 处理确认失败的订单
     *
     * @param order   订单
     * @param failure 确认失败订单
     */
    private void handleConfirmFailureOrder(OrderBO order, OrderConfirmResultBO.ConfirmFailureBO failure) {
        try {
            transactionTemplate.executeWithoutResult(transactionStatus -> {
                UpdateOrderBO updateOrder = new UpdateOrderBO();
                updateOrder.setOrderSn(order.getOrderSn());
                updateOrder.setSource(OperateSourceConstants.SYSTEM);
                updateOrder.setDescription(OrderOperateConstants.SYSTEM_ASYNC_CONFIRM_ORDER);
                updateOrder.setChannelTradeOrderSn(failure.getChannelTradeOrderSn());
                updateOrder.setErrorInfo(failure.getTruncationErrorInfo());
                updateOrder.setOrderTag(order.addTag(OrderTagEnum.REPAIRING.getValue()));
                updateOrder.setOrderStatus(Pair.of(order.getOrderStatus(), OrderStatusEnum.FAILURE.getValue()));
                updateOrder.setLogChangeItemList(order.diff(updateOrder).getDiffs());
                boolean b = orderService.updateOrderByOrderSn(updateOrder);
                if (!b) {
                    log.info("处理确认失败订单更新订单失败: updateOrderBO={}", JSON.toJSONString(updateOrder));
                    return;
                }
                SaveOrderRepairBO saveOrderRepair = orderRepairService.genSaveOrderRepair(order, failure.getErrorCode(), failure.getTruncationErrorInfo());
                orderRepairService.saveRepairOrderList(Lists.newArrayList(saveOrderRepair));
            });
        } catch (Exception e) {
            log.warn("处理确认失败订单发生异常: [orderBO={},failureBO={}]", JSON.toJSONString(order), JSON.toJSONString(failure), e);
        }
    }


    /**
     * 校验异步确认订单数据
     */
    private boolean validOrder(List<OrderBO> orderList, OrderConfirmMessage orderConfirmMessage) {
        // 校验订单是否存在
        String supplyTradeSn = orderConfirmMessage.getSupplyTradeSn();
        List<String> orderSnList = orderConfirmMessage.getOrderSnList();
        if (CollectionUtils.isEmpty(orderList)) {
            if(log.isDebugEnabled()) {
                log.debug("订单不存在 param={}", orderConfirmMessage);
            }
            DingDingExtUtils.sendOrderErrorMessage(null, "订单不存在", null, supplyTradeSn, orderSnList, null, null);
            return false;
        } else if (CollectionUtils.isNotEmpty(orderSnList)) {
            if (orderList.size() != orderSnList.size()) {
                if(log.isDebugEnabled()) {
                    log.debug("部分订单不存在,不存在订单号={},param={},", orderConfirmMessage, orderSnList);
                }
                DingDingExtUtils.sendOrderErrorMessage(null, "部分订单不存在", null, supplyTradeSn, orderSnList, null, null);
                return false;
            }
        }
        // 校验订单状态
        List<String> invalidOrderSnList = orderList.stream().filter(item -> EnumUtils.neq(OrderStatusEnum.RECHARGE, item.getOrderStatus()))
                .map(OrderBO::getOrderSn).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(invalidOrderSnList)) {
            if(log.isDebugEnabled()) {
                log.debug("存在非处理中状态的订单 {}", invalidOrderSnList);
            }
            DingDingExtUtils.sendOrderErrorMessage(null, "确认订单状态异常", null, supplyTradeSn, invalidOrderSnList, null, null);
            return false;
        }
        return true;
    }

    /**
     * 校验大额订单或虚拟渠道订单商品的成本价和状态
     */
    private ValidResult validOrderProduct(List<OrderBO> orderList) {
        List<PlatformPriceCheckDTO> platformPriceCheckList = orderList.stream()
                .filter(order -> OrderTagEnum.isLargeAmountOrder(order.getOrderTag()) || ChannelCodeUtils.isVirtual(order.getChannelCode()))
                .map(OrderBO::getOrderProductList).filter(Objects::nonNull).flatMap(Collection::stream)
                .map(item -> PlatformPriceCheckDTO.builder().platformPrice(item.getPlatformPrice()).skuCode(item.getSkuCode()).build())
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(platformPriceCheckList)) {
            return new ValidResult(orderList, Collections.emptyList());
        }
        PlatformPriceCheckBO platformPriceCheck = productCenterApiClient.checkPlatformPriceAndState(platformPriceCheckList);
        if (platformPriceCheck.existsErrorSku()) {
            Map<String, PlatformPriceCheckBO.ErrorSkuInfo> errorSkuCodeMap = platformPriceCheck.getErrorSkuCodeList().stream().collect(Collectors.toMap(item -> item.getErrorSkuCode(), Function.identity(), (o1, o2) -> o1));
            ArrayList<OrderBO> successList = Lists.newArrayList();
            ArrayList<ErrorOrder> errorList = Lists.newArrayList();
            for (OrderBO order : orderList) {
                List<PlatformPriceCheckBO.ErrorSkuInfo> errorSkuInfoList = order.getOrderProductList().stream().map(orderProduct -> errorSkuCodeMap.get(orderProduct.getSkuCode())).filter(Objects::nonNull).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(errorSkuInfoList)) {
                    errorList.add(new ErrorOrder(order, errorSkuInfoList));
                } else {
                    successList.add(order);
                }
            }
            return new ValidResult(successList, errorList);
        } else {
            return new ValidResult(orderList, Collections.emptyList());
        }
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    private class ValidResult {

        private List<OrderBO> successList;

        private List<ErrorOrder> errorOrderList;

    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    private class ErrorOrder {

        private OrderBO order;

        private List<PlatformPriceCheckBO.ErrorSkuInfo> errorSkuInfoList;

        /**
         * 获取第一个错误编码
         */
        public Integer getFirstErrorCode() {
            return errorSkuInfoList.stream().findFirst().map(item -> item.getErrorCode()).orElse(GlobalErrorCodeEnum.PRODUCT_ERROR.getCode());
        }

        /**
         * 获取错误信息描述
         *
         * @param maxLength 返回的最大长度
         */
        public String errorMessage(Integer maxLength) {
            if (CollectionUtils.isEmpty(errorSkuInfoList)) {
                return StringPool.EMPTY;
            }
            StringBuilder stringBuilder = new StringBuilder();
            for (PlatformPriceCheckBO.ErrorSkuInfo errorSkuInfo : errorSkuInfoList) {
                stringBuilder.append(String.format("SKU编码%s:%s", errorSkuInfo.getErrorSkuCode(), errorSkuInfo.getErrorMessage())).append(StringPool.SEMICOLON);
            }
            int length = stringBuilder.length();
            if (maxLength != null && length > maxLength) {
                stringBuilder.setLength(maxLength);
            }
            return stringBuilder.toString();
        }

    }
}
